//#define _CRTDBG_MAP_ALLOC
////#define _CRTDBG_MAP_ALLOC
//#include <stdlib.h>
//#include <crtdbg.h>


//#include "../vld/vld.h"

//#pragma comment(lib, "../vld/vld.lib")
//#pragma comment(lib, "../vld/vldmtdll.lib")

#include <iostream>
#include <process.h>

#include <remotefunction.h>


const std::string g_pipename = "\\\\.\\pipe\\testmt";

kog::pipe::winobject g_pipeevent;
kog::remote_function* g_rfServer = NULL;
kog::remote_function* g_rfClient = NULL;

int add(int a, int b)
{
	return a + b;
}

void call(void* param)
{
	kog::remote_function* rf = (kog::remote_function*)param;
	const char* ptr = g_rfServer == rf ? "server" : "client";
	//for (int i = 0; i < 10; ++ i)
	while (true)
	{
		try {
			int a = rand();
			int b = rand();
			int c = (*rf)["add"].makecall<int>(a, b);

			if (add(a, b) != c)
			{
				printf("[%s] error %d + %d != %d\n", ptr, a, b, c);
			}
			else printf("[%s] %d + %d == %d\n", ptr, a, b, c);
		} catch (std::exception& ex) {
			printf("[%s] exception (%s)\n", ptr, ex.what());
			break;
		}
	}
	printf("[%s] call done.\n", ptr);
}

void server(void* param)
{
	kog::pipe pipeServer(g_pipename, kog::pipe::server_port);
	g_pipeevent.release();
	pipeServer.waitclient();
	

	int fid, tid, dtype;
	kog::pipe::msgpeice_t msg;
	pipeServer.recv(fid, tid, dtype, msg);
	printf("[server] recv (%d -> %d) %s\n", fid, tid, msg.ptr);
	delete msg.ptr;

	kog::remote_function rfServer(pipeServer);
	rfServer.entry("add", add);

	g_rfServer = &rfServer;
	// start call thread
	_beginthread(call, 0, &rfServer);
	_beginthread(call, 0, &rfServer);
	
	rfServer.start_service();
	

	printf("server done.\n");
}

void client(void* param)
{
	g_pipeevent.wait();
	kog::os::osobject::sleep(100);
	kog::pipe pipeClient(g_pipename, kog::pipe::client_port);
	pipeClient.connectserver();
	const char* tmp = "Hello, world!";
	kog::pipe::msgpeice_t m;
	m.ptr = tmp;
	m.len = strlen(tmp) + 1;
	pipeClient.send(0, 1, 0, &m, 1);

	kog::remote_function rfClient(pipeClient);
	rfClient.entry("add", add);

	g_rfClient = &rfClient;
	_beginthread(call, 0, &rfClient);
	_beginthread(call, 0, &rfClient);
	
	rfClient.start_service();

	printf("client done.\n");
}

int main(int argc, const char* argv[])
{
	//_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
	//int* a = new int;
	g_pipeevent.create_event(false);

	kog::os::osobject hserver;
	kog::os::osobject hclient;
	hserver.create_thread(kog::unary2zero(std::ptr_fun(server), (void*)NULL));
	hclient.create_thread(kog::unary2zero(std::ptr_fun(client), (void*)NULL));


	//Sleep(5 * 1000);
	kog::os::osobject::sleep(5 * 1000);
	g_rfClient->stop_service();
	g_rfServer->stop_service();


	hserver.wait();
	hclient.wait();

	hserver.close();
	hclient.close();
	g_pipeevent.close();

	//_CrtDumpMemoryLeaks();
	return 0;
}